﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

namespace TeamFoundationServerSensor {

    /// <summary>
    /// Enumeratable log types.
    /// </summary>
    internal enum LogLevel { Error, Warning, Info, Trace };

    internal class Logger {

        /// <summary>
        /// Singleton instance of the class.
        /// </summary>
        internal static readonly Logger TheInstance = new Logger();

        /// <summary>
        /// Specify whether to enable trace logging.
        /// </summary>
        private readonly Boolean TRACE_ENABLED = true;

        /// <summary>
        /// Path to the logging directory.
        /// </summary>
        private string logPath;

        /// <summary>
        /// Constructor used in Singleton design.
        /// </summary>
        private Logger() {
            this.logPath = ".";
        }

        /// <summary>
        /// Basic initializer when writing to a file.
        /// </summary>
        /// <param name="logPath">The path location the log file is to
        /// be written to.</param>
        internal void Initialize(string logPath) {
            this.logPath = logPath;
        }

        /// <summary>
        /// Logs any controller message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="logLevel">The enumerated log level type.</param>
        internal void Log(string message, LogLevel logLevel) {

            // Create the line of text to write.
            string line = DateTime.Now.ToString() + " [" 
                + logLevel.ToString() + "] " + message 
                + System.Environment.NewLine;

            // Only write trace data if trace is enabled.
            if ((TRACE_ENABLED && logLevel.Equals(LogLevel.Trace))
                || (!logLevel.Equals(LogLevel.Trace))) {

                // Write once to the console if it is available. 
                System.Console.Write(line);

                // Write to the log file.
                LogtoFile(line, logLevel);
            }
        }

        /// <summary>
        /// Helper method to log a message to a file.
        /// </summary>
        /// <param name="message">The message</param>
        /// <param name="logLevel">The loglevel</param>
        private void LogtoFile(string message, LogLevel logLevel) {
            
            // Attempt to write the log to a file.
            try {

                // Open the file for writing. 
                FileStream fs = new FileStream(logPath,
                    FileMode.Append, FileAccess.Write);
                StreamWriter sw = new StreamWriter(fs);

                // Go to the end of the file and write a line.
                sw.BaseStream.Seek(0, SeekOrigin.End);
                sw.Write(message);

                // Close the text stream and the file.
                sw.Flush();
                fs.Close();
            }
            catch (Exception e) {

                // It would be pretty silly to write to the log if we had an
                // error while writing to the log the first time.
                e.Source = "LoggerWriting";
                Log(e);
            }
        }

        /// <summary>
        /// Method to handle logging when a program has an exception.
        /// </summary>
        /// <param name="exception">The exception that was thrown.</param>
        internal void Log(Exception exception) {

            // Check to make sure it was not this class which threw the
            // exception
            if (exception.Source.Equals("LoggerWriting")) {

                // Only thing we can do.
                System.Console.WriteLine(exception.Message 
                    + System.Environment.NewLine + exception.StackTrace);
            
            }
            else {
                this.Log(exception.Message, LogLevel.Error);
                this.Log(exception.StackTrace, LogLevel.Error);
            }
        }
    }
}